package com.cl.security.system.service;

import com.cl.security.common.result.CommonResult;
import com.cl.security.common.util.JwtTokenUtil;
import com.cl.security.system.entity.*;
import com.cl.security.system.repository.RoleRepository;
import com.cl.security.system.repository.UserRepository;
import com.cl.security.base.service.BaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author chenlong
 * @date 2020/12/8
 * /111
 */
@Service
public class UserService extends BaseService<User,UserRepository> {
    private final static Logger LOGGER = LoggerFactory.getLogger(UserService.class);
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final FileInfoService fileInfoService;

    protected UserService(UserRepository userRepository, RoleRepository roleRepository, FileInfoService fileInfoService) {
        super(userRepository);
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.fileInfoService = fileInfoService;
    }

    public CommonResult saveAvatar(MultipartFile file,Long id) {
        FileInfo avatar = fileInfoService.upload(file).getData();
        if (avatar != null) {
            User user = userRepository.findById(id).get();
            user.setAvatar(avatar);
            userRepository.save(user);
            return CommonResult.success(avatar);
        }
        return CommonResult.failed("上传失败");
    }


    public User getUserByUsername(String username) {
        Specification<User> specification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("username"), username);
            }
        };
        Optional<User> user = userRepository.findOne(specification);
        return user.orElse(null);

    }
    public CommonResult examPassword(Long id, String password) {
        User user = userRepository.findById(id).get();
        if (passwordEncoder.matches(password, user.getPassword())) {
            return CommonResult.success(true);
        }
        return CommonResult.success(false);
    }
    public String login(String username, String password) {
        String token = null;
        try {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            token = JwtTokenUtil.generateToken(userDetails);
        } catch (AuthenticationException e) {
            LOGGER.warn("登录异常：{}" + e.getMessage());
        }
        return token;
    }
    @Override
    public CommonResult save(User userParam) {
        if (userParam.getId() == null && emailRegistered(userParam.getEmail())) {
            return CommonResult.failed("该邮箱已被注册");
        }
        User oldUser = null;
        User user = new User();
        BeanUtils.copyProperties(userParam, user);
        if (user.getId() == null) {
            Specification<User> specification =
                    (Specification<User>) (root, criteriaQuery, criteriaBuilder) ->
                            criteriaBuilder.equal(root.get("username"), userParam.getUsername());

            if (!userRepository.findAll(specification).isEmpty()) {
                return CommonResult.failed("用户名已存在");
            }
            String password = user.getPassword() == null ? "123456" : user.getPassword();
            String encodePassword = passwordEncoder.encode(password);
            user.setPassword(encodePassword);
            Set<Role> roles = new HashSet<>();
            roles.add(roleRepository.findById(1L).get());
            user.setRoles(roles);
            FileInfo avatar = fileInfoService.fileRepository.findById(22L).get();
            user.setAvatar(avatar);
        } else{
            oldUser = userRepository.findById(user.getId()).get();
            if (user.getPassword()!=null &&!user.getPassword().equals(oldUser.getPassword())) {
                String encodePassword = passwordEncoder.encode(user.getPassword());
                user.setPassword(encodePassword);
            }else {
                user.setPassword(oldUser.getPassword());
            }

        }
        userRepository.save(user);
        return CommonResult.success("操作成功");
    }

    public Set<Permission> listPermission(Long id) {
        Optional<User> userOptional = userRepository.findById(id);
        Set<Permission> permissions = new HashSet<>();
        userOptional.ifPresent(user -> user.getRoles().forEach(role ->
                permissions.addAll(role.getPermissions())
        ));
        return permissions;
    }

    public Long getUserIdFromRequest(HttpServletRequest httpServletRequest) {
        // 获取http请求头中的token
        String authHeader = httpServletRequest.getHeader(this.tokenHeader);
        if (authHeader != null && authHeader.startsWith(tokenHead)) {
            String authToken = authHeader.substring(this.tokenHead.length());
            String username = JwtTokenUtil.getUserNameFromToken(authToken);
            Specification<User> specification = (Specification<User>) (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("username"), username);
            List<User> users = userRepository.findAll(specification);
            if (users.size() > 0) {
                return users.get(0).getId();
            }
        }
        return null;
    }

    public User getUserByToken(String token) {
        String username = JwtTokenUtil.getUserNameFromToken(token);
        return getUserByUsername(username);
    }

    protected boolean emailRegistered(String email) {
        Specification<User> specification = (Specification<User>) ((root, cq, cb) -> {
            cq.where(
                    cb.and(
                            cb.equal(root.get("email"), email)
                    )
            );
            return cq.getRestriction();
        });
        return userRepository.findAll(specification).size() > 0;
    }

}
